home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / Source / Chapter 13 / Game / PlayerManager.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2005-03-29  |  12.7 KB  |  357 lines

  1. //-----------------------------------------------------------------------------
  2. // PlayerManager.h implementation.
  3. // Refer to the PlayerManager.h interface for more details.
  4. //
  5. // Programming a Multiplayer First Person Shooter in DirectX
  6. // Copyright (c) 2004 Vaughan Young
  7. //-----------------------------------------------------------------------------
  8. #include "Main.h"
  9.  
  10. //-----------------------------------------------------------------------------
  11. // Player manager class constructor.
  12. //-----------------------------------------------------------------------------
  13. PlayerManager::PlayerManager()
  14. {
  15.     // Create the list of player objects.
  16.     m_players = new LinkedList< PlayerObject >;
  17.     m_viewingPlayer = NULL;
  18.  
  19.     // Clear all the local player's movement details.
  20.     m_localMovement = false;
  21.     m_localDrive = 0.0f;
  22.     m_localStrafe = 0.0f;
  23.     m_localFire = false;
  24.  
  25.     // Indicate that the local player needs to be spawned.
  26.     m_spawnLocalPlayer = true;
  27.     m_requestedSpawnPoint = false;
  28. }
  29.  
  30. //-----------------------------------------------------------------------------
  31. // Player manager class destructor.
  32. //-----------------------------------------------------------------------------
  33. PlayerManager::~PlayerManager()
  34. {
  35.     // Destroy the list of player objects.
  36.     m_players->ClearPointers();
  37.     SAFE_DELETE( m_players );
  38. }
  39.  
  40. //-----------------------------------------------------------------------------
  41. // Updates all of the players.
  42. //-----------------------------------------------------------------------------
  43. void PlayerManager::Update( float elapsed )
  44. {
  45.     // Ensure the scene is loaded.
  46.     if( g_engine->GetSceneManager()->IsLoaded() == false )
  47.         return;
  48.  
  49.     // Get a pointer to the local player.
  50.     PlayerObject *localPlayer = m_players->GetFirst();
  51.     if( localPlayer == NULL )
  52.         return;
  53.  
  54.     // Check if the local player is dead.
  55.     if( localPlayer->GetHealth() <= 0.0f && m_spawnLocalPlayer == false )
  56.     {
  57.         // Spawn the local player on a left mouse button press.
  58.         if( g_engine->GetInput()->GetButtonPress( 0 ) == true )
  59.             m_spawnLocalPlayer = true;
  60.  
  61.         return;
  62.     }
  63.  
  64.     // If the local player needs to be spawned and a spawn point hasn't already
  65.     // been requested, then request a spawn point from the host.
  66.     if( m_spawnLocalPlayer == true && m_requestedSpawnPoint == false )
  67.     {
  68.         // Send a request spawn point message to the host.
  69.         NetworkMessage rspm;
  70.         rspm.msgid = MSGID_SPAWN_POINT_REQUEST;
  71.         rspm.dpnid = g_engine->GetNetwork()->GetLocalID();
  72.         g_engine->GetNetwork()->Send( &rspm, sizeof( NetworkMessage ), g_engine->GetNetwork()->GetHostID() );
  73.  
  74.         // Indicate that a spawn point has been requested.
  75.         m_requestedSpawnPoint = true;
  76.  
  77.         return;
  78.     }
  79.     else if( m_spawnLocalPlayer == true )
  80.     {
  81.         // The local player needs to be spawned, but a spawn point has already
  82.         // been requested. So just return and wait for the request response.
  83.         return;
  84.     }
  85.  
  86.     // Calculate a delayed elapsed time, used for smoothing out view movement.
  87.     static float delayedElapsed = 0.0f;
  88.     delayedElapsed = delayedElapsed * 0.99f + elapsed * 0.01f;
  89.  
  90.     // Skip any further input if the local player is dying.
  91.     if( localPlayer->GetDying() == true )
  92.         return;
  93.  
  94.     // It is impossible to send network messages for every mouse movement,
  95.     // therefore the player's looking direction will be updated directly.
  96.     localPlayer->MouseLook( (float)g_engine->GetInput()->GetDeltaY() * delayedElapsed, (float)g_engine->GetInput()->GetDeltaX() * delayedElapsed );
  97.  
  98.     // Send a periodic player look update to sync the other players.
  99.     static unsigned long lookUpdate = timeGetTime();
  100.     if( lookUpdate + 100 < timeGetTime() && localPlayer->GetEnabled() == true )
  101.     {
  102.         PlayerLookUpdateMsg plum;
  103.         plum.msgid = MSGID_PLAYER_LOOK_UPDATE;
  104.         plum.dpnid = localPlayer->GetID();
  105.         plum.viewTilt = localPlayer->GetViewTilt();
  106.         plum.rotationY = localPlayer->GetRotation().y;
  107.         g_engine->GetNetwork()->Send( &plum, sizeof( PlayerLookUpdateMsg ), DPNID_ALL_PLAYERS_GROUP, DPNSEND_NOLOOPBACK );
  108.  
  109.         lookUpdate = timeGetTime();
  110.     }
  111.  
  112.     // Used for storing the local player's desired movement.
  113.     float desiredDrive = 0.0f;
  114.     float desiredStrafe = 0.0f;
  115.     bool desiredFire = false;
  116.  
  117.     // Check if the local player is trying to drive fowards or backwards.
  118.     if( g_engine->GetInput()->GetKeyPress( DIK_W, true ) )
  119.         desiredDrive = 1.0;
  120.     else if( g_engine->GetInput()->GetKeyPress( DIK_S, true ) )
  121.         desiredDrive = -1.0;
  122.  
  123.     // Check if the local player is trying to strafe left or right.
  124.     if( g_engine->GetInput()->GetKeyPress( DIK_D, true ) )
  125.         desiredStrafe = 1.0;
  126.     else if( g_engine->GetInput()->GetKeyPress( DIK_A, true ) )
  127.         desiredStrafe = -1.0;
  128.  
  129.     // Check if the local player is trying to fire their weapon.
  130.     desiredFire = g_engine->GetInput()->GetButtonPress( 0, true );
  131.  
  132.     // Check if we need to drive the local player.
  133.     if( m_localDrive != desiredDrive )
  134.     {
  135.         m_localDrive = desiredDrive;
  136.         m_localMovement = true;
  137.     }
  138.  
  139.     // Check if we need to strafe the local player.
  140.     if( m_localStrafe != desiredStrafe )
  141.     {
  142.         m_localStrafe = desiredStrafe;
  143.         m_localMovement = true;
  144.     }
  145.  
  146.     // Check if we need to fire the local player's weapon.
  147.     if( m_localFire != desiredFire )
  148.     {
  149.         m_localFire = desiredFire;
  150.         m_localMovement = true;
  151.     }
  152.  
  153.     // If the local player's movement changed or the move update timer expires,
  154.     // update the local player across the network. Since the network message is
  155.     // sent using DPNSEND_NOLOOPBACK, the local player will need to update too.
  156.     static unsigned long moveUpdate = timeGetTime();
  157.     if( ( m_localMovement == true || moveUpdate + 200 < timeGetTime() ) && localPlayer->GetEnabled() == true )
  158.     {
  159.         PlayerMoveUpdateMsg pmum;
  160.         pmum.msgid = MSGID_PLAYER_MOVE_UPDATE;
  161.         pmum.dpnid = localPlayer->GetID();
  162.         pmum.translation = localPlayer->GetTranslation();
  163.         pmum.drive = m_localDrive;
  164.         pmum.strafe = m_localStrafe;
  165.         pmum.fire = m_localFire;
  166.         g_engine->GetNetwork()->Send( &pmum, sizeof( PlayerMoveUpdateMsg ), DPNID_ALL_PLAYERS_GROUP, DPNSEND_NOLOOPBACK );
  167.         m_localMovement = false;
  168.  
  169.         localPlayer->SetDrive( m_localDrive );
  170.         localPlayer->SetStrafe( m_localStrafe );
  171.         localPlayer->SetFire( m_localFire );
  172.  
  173.         moveUpdate = timeGetTime();
  174.     }
  175.  
  176.     // Check if the local player wants to change weapons with the scroll wheel.
  177.     char changeWeapon = 0;
  178.     if( g_engine->GetInput()->GetDeltaWheel() > 0 )
  179.         changeWeapon = 1;
  180.     else if( g_engine->GetInput()->GetDeltaWheel() < 0 )
  181.         changeWeapon = -1;
  182.  
  183.     // Change the local player's weapon if the scroll wheel moved.
  184.     if( changeWeapon != 0 )
  185.         localPlayer->ChangeWeapon( changeWeapon );
  186.  
  187.     // Check if the local player is trying to change to a specific weapon.
  188.     if( g_engine->GetInput()->GetKeyPress( DIK_1 ) == true )
  189.         localPlayer->ChangeWeapon( 0, 0 );
  190.     if( g_engine->GetInput()->GetKeyPress( DIK_2 ) == true )
  191.         localPlayer->ChangeWeapon( 0, 1 );
  192.     if( g_engine->GetInput()->GetKeyPress( DIK_3 ) == true )
  193.         localPlayer->ChangeWeapon( 0, 2 );
  194.     if( g_engine->GetInput()->GetKeyPress( DIK_4 ) == true )
  195.         localPlayer->ChangeWeapon( 0, 3 );
  196.     if( g_engine->GetInput()->GetKeyPress( DIK_5 ) == true )
  197.         localPlayer->ChangeWeapon( 0, 4 );
  198.     if( g_engine->GetInput()->GetKeyPress( DIK_6 ) == true )
  199.         localPlayer->ChangeWeapon( 0, 5 );
  200.     if( g_engine->GetInput()->GetKeyPress( DIK_7 ) == true )
  201.         localPlayer->ChangeWeapon( 0, 6 );
  202.     if( g_engine->GetInput()->GetKeyPress( DIK_8 ) == true )
  203.         localPlayer->ChangeWeapon( 0, 7 );
  204.     if( g_engine->GetInput()->GetKeyPress( DIK_9 ) == true )
  205.         localPlayer->ChangeWeapon( 0, 8 );
  206.     if( g_engine->GetInput()->GetKeyPress( DIK_0 ) == true )
  207.         localPlayer->ChangeWeapon( 0, 9 );
  208. }
  209.  
  210. //-----------------------------------------------------------------------------
  211. // Spawns the local player using the given spawn point.
  212. //-----------------------------------------------------------------------------
  213. void PlayerManager::SpawnLocalPlayer( long spawnPoint )
  214. {
  215.     // Ensure the spawn point request was successful.
  216.     if( spawnPoint == -1 )
  217.     {
  218.         // End the spawn point request so a new one can be attempted.
  219.         m_requestedSpawnPoint = false;
  220.  
  221.         // Indicate that the local player needs to be spawned.
  222.         m_spawnLocalPlayer = true;
  223.  
  224.         return;
  225.     }
  226.  
  227.     // Send a message to spawn the local player at the given spawn point.
  228.     SpawnPlayerMsg spm;
  229.     spm.msgid = MSGID_SPAWN_PLAYER;
  230.     spm.dpnid = g_engine->GetNetwork()->GetLocalID();
  231.     spm.translation = g_engine->GetSceneManager()->GetSpawnPointByID( spawnPoint )->GetTranslation();
  232.     g_engine->GetNetwork()->Send( &spm, sizeof( SpawnPlayerMsg ), DPNID_ALL_PLAYERS_GROUP );
  233. }
  234.  
  235. //-----------------------------------------------------------------------------
  236. // Spawns the given player at the given translation.
  237. //-----------------------------------------------------------------------------
  238. void PlayerManager::SpawnPlayer( DPNID dpnid, D3DXVECTOR3 translation )
  239. {
  240.     // Find the player to spawn.
  241.     m_players->Iterate( true );
  242.     while( m_players->Iterate() )
  243.         if( m_players->GetCurrent()->GetID() == dpnid )
  244.             break;
  245.     if( m_players->GetCurrent() == NULL )
  246.         return;
  247.  
  248.     // Enable the player object.
  249.     m_players->GetCurrent()->SetEnabled( true );
  250.     m_players->GetCurrent()->SetVisible( true );
  251.  
  252.     // Restore the player's health.
  253.     m_players->GetCurrent()->SetHealth( 100.0f );
  254.     m_players->GetCurrent()->SetDying( false );
  255.  
  256.     // Play the idle animation twice to ensure that both animation tracks 
  257.     // contain the idle animation data. This will prevent players from 
  258.     // transitioning from the death animation when respawning. 
  259.     m_players->GetCurrent()->PlayAnimation( 0, 0.0f ); 
  260.     m_players->GetCurrent()->PlayAnimation( 0, 0.0f );
  261.  
  262.     // Set the player's translation and rotation.
  263.     m_players->GetCurrent()->SetTranslation( translation );
  264.     m_players->GetCurrent()->MouseLook( 0.0f, 0.0f, true );
  265.  
  266.     // Check if the local player was spawned.
  267.     if( m_players->GetCurrent()->GetID() == g_engine->GetNetwork()->GetLocalID() )
  268.     {
  269.         // Set local player as the viewing player.
  270.         m_players->GetCurrent()->SetIsViewing( true );
  271.         m_viewingPlayer = m_players->GetCurrent();
  272.  
  273.         // The request for a local player spawn point was successful.
  274.         m_requestedSpawnPoint = false;
  275.  
  276.         // Indicate that the local player has been spawned.
  277.         m_spawnLocalPlayer = false;
  278.     }
  279.     else
  280.         m_players->GetCurrent()->SetIsViewing( false );
  281. }
  282.  
  283. //-----------------------------------------------------------------------------
  284. // Adds a new player.
  285. //-----------------------------------------------------------------------------
  286. PlayerObject *PlayerManager::AddPlayer( PlayerInfo *player )
  287. {
  288.     // Create the script for the player's character.
  289.     Script *script = new Script( ( (PlayerData*)player->data )->character, "./Assets/Characters/" );
  290.  
  291.     // Create the player object.
  292.     PlayerObject *object = m_players->Add( new PlayerObject( player, script ) );
  293.  
  294.     // Destroy the character script.
  295.     SAFE_DELETE( script );
  296.  
  297.     return object;
  298. }
  299.  
  300. //-----------------------------------------------------------------------------
  301. // Removes the specified player.
  302. //-----------------------------------------------------------------------------
  303. void PlayerManager::RemovePlayer( DPNID dpnid )
  304. {
  305.     // Find the player to remove.
  306.     m_players->Iterate( true );
  307.     while( m_players->Iterate() )
  308.         if( m_players->GetCurrent()->GetID() == dpnid )
  309.             break;
  310.     if( m_players->GetCurrent() == NULL )
  311.         return;
  312.  
  313.     // Remove the player object.
  314.     PlayerObject *player = m_players->GetCurrent();
  315.     m_players->Remove( &player );
  316. }
  317.  
  318. //-----------------------------------------------------------------------------
  319. // Returns the local player.
  320. //-----------------------------------------------------------------------------
  321. PlayerObject *PlayerManager::GetLocalPlayer()
  322. {
  323.     return m_players->GetFirst();
  324. }
  325.  
  326. //-----------------------------------------------------------------------------
  327. // Returns the specified player.
  328. //-----------------------------------------------------------------------------
  329. PlayerObject *PlayerManager::GetPlayer( DPNID dpnid )
  330. {
  331.     m_players->Iterate( true );
  332.     while( m_players->Iterate() )
  333.         if( m_players->GetCurrent()->GetID() == dpnid )
  334.             return m_players->GetCurrent();
  335.  
  336.     return NULL;
  337. }
  338.  
  339. //-----------------------------------------------------------------------------
  340. // Returns the next iterated player from the player list.
  341. //-----------------------------------------------------------------------------
  342. PlayerObject *PlayerManager::GetNextPlayer( bool restart )
  343. {
  344.     m_players->Iterate( restart );
  345.     if( restart == true )
  346.         m_players->Iterate();
  347.  
  348.     return m_players->GetCurrent();
  349. }
  350.  
  351. //-----------------------------------------------------------------------------
  352. // Returns the currently viewing player.
  353. //-----------------------------------------------------------------------------
  354. PlayerObject *PlayerManager::GetViewingPlayer()
  355. {
  356.     return m_viewingPlayer;
  357. }